package com.dimenlink.web.controller;

import com.dimenlink.component.RedisComponent;
import com.dimenlink.entity.config.AppConfig;
import com.dimenlink.entity.constants.Constants;
import com.dimenlink.entity.dto.SysSettingDto;
import com.dimenlink.entity.dto.TokenUserInfoDto;
import com.dimenlink.entity.dto.UploadingFileDto;
import com.dimenlink.entity.enums.DateTimePatternEnum;
import com.dimenlink.entity.enums.ResponseCodeEnum;
import com.dimenlink.entity.po.VideoInfoFile;
import com.dimenlink.entity.vo.ResponseVO;
import com.dimenlink.exception.BusinessException;
import com.dimenlink.service.VideoInfoFileService;
import com.dimenlink.utils.DateUtil;
import com.dimenlink.utils.FFmpegUtils;
import com.dimenlink.utils.StringTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;

@RestController
@RequestMapping("/file")
@Validated
@Slf4j
public class FileController extends ABaseController{
    @Resource
    private AppConfig appConfig;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private FFmpegUtils ffmpegUtils;

    @Resource
    private VideoInfoFileService videoInfoFileService;

    @RequestMapping("/getResource")
    public void getResource(HttpServletResponse response, @NotNull String sourceName) throws IOException {
        if(!StringTools.pathIsOk(sourceName)){
            throw  new BusinessException(ResponseCodeEnum.CODE_600);
        }
        String suffix = StringTools.getFileSuffix(sourceName);
        response.setContentType("image/" + suffix.replace(".", ""));
        response.setHeader("Cache-Control", "max-age=2592000");
        readFile(response, sourceName);
    }

    /**
     * 读取文件
     * @param response
     * @param filePath
     */
    private void readFile(HttpServletResponse response, String filePath) {
        // 构造完整的文件路径并创建File对象
        File file = new File(appConfig.getProjectFolder() + filePath);
        if (!file.exists()) {
            return;
        }
        try (OutputStream out = response.getOutputStream();
             FileInputStream in = new FileInputStream(file)) {
            // 创建1KB的缓冲区用于分块读取文件
            byte[] byteData = new byte[1024];
            int len = 0;
            // 循环读取文件内容直至文件末尾
            while ((len = in.read(byteData)) != -1) {
                // 将读取到的数据写入响应输出流
                out.write(byteData, 0, len);
            }

            // 强制刷新输出流，确保所有数据都发送到客户端
            out.flush();
        } catch (Exception e) {
            // 记录文件读取过程中的异常信息
            log.error("读取文件异常", e);
        }
    }

    @RequestMapping("/preUploadVideo")
    public ResponseVO preUploadVideo(@NotEmpty String fileName, @NotNull Integer chunks) {
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();
        String uploadId = redisComponent.savePreVideoFileInfo(tokenUserInfoDto.getUserId(), fileName, chunks);
        return getSuccessResponseVO(uploadId);
    }

    @RequestMapping("/uploadVideo")
    public ResponseVO uploadVideo(@NotNull MultipartFile chunkFile,
                                  @NotNull Integer chunkIndex,
                                  @NotEmpty String uploadId) throws IOException {
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();
        UploadingFileDto fileDto = redisComponent.getUploadVideoFile(tokenUserInfoDto.getUserId(), uploadId);
        if(fileDto == null){
            throw new BusinessException("文件不存在，请重新上传");
        }
        SysSettingDto sysSettingDto = redisComponent.getSysSettingDto();
        if(fileDto.getFileSize() > sysSettingDto.getVideoSize() * Constants.MB_SIZE){
            throw new BusinessException("文件大小超出限制");
        }

        //判断分片
        if((chunkIndex-1)> fileDto.getChunkIndex() || chunkIndex > fileDto.getChunks()-1){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        String folder = appConfig.getProjectFolder() + Constants.FILE_FOLDER +
                Constants.FILE_FOLDER_TEMP+ fileDto.getFilePath();
        File targetFile = new File(folder + "/" + chunkIndex);
        chunkFile.transferTo(targetFile);
        fileDto.setChunkIndex(chunkIndex);
        fileDto.setFileSize(fileDto.getFileSize()+chunkFile.getSize());
        redisComponent.updatePreVideoFileInfo(tokenUserInfoDto.getUserId(), fileDto);

        return getSuccessResponseVO(null);
    }

    @RequestMapping("/delUploadVideo")
    public ResponseVO delUploadVideo(@NotEmpty String uploadId) throws IOException {
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();
        UploadingFileDto fileDto = redisComponent.getUploadVideoFile(tokenUserInfoDto.getUserId(), uploadId);
        if(fileDto == null){
            throw new BusinessException("文件不存在，请重新上传");
        }
        redisComponent.delVideoFileInfo(tokenUserInfoDto.getUserId(), uploadId);
        FileUtils.deleteDirectory(new File(appConfig.getProjectFolder()  + Constants.FILE_FOLDER + Constants.FILE_FOLDER_TEMP+ fileDto.getFilePath()));

        return getSuccessResponseVO(null);
    }

    @RequestMapping("/uploadImage")
    public ResponseVO uploadImage(@NotNull MultipartFile  file, @NotNull Boolean createThumbnail) throws IOException {
        String day = DateUtil.format(new Date(), DateTimePatternEnum.YYYY_MM_DD.getPattern());
        String folder = appConfig.getProjectFolder() + Constants.FILE_FOLDER  + Constants.FILE_COVER + day;
        File folderFile = new File(folder);
        if(!folderFile.exists()){
            folderFile.mkdirs();
        }
        String fileName = file.getOriginalFilename();
        String fileSuffix = StringTools.getFileSuffix(fileName);
        String realFileName = StringTools.getRandomString(Constants.LENGTH_30) + fileSuffix;
        String filePath = folder + "/" + realFileName;
        file.transferTo(new File(filePath));
        if(createThumbnail){
            //创建缩略图
            ffmpegUtils.createImageThumbnail(filePath);
        }

        return getSuccessResponseVO(Constants.FILE_COVER + day + "/" + realFileName);
    }

    /**
     * 获取视频资源
     * @param response
     * @param fileId
     */
    @RequestMapping("/videoResource/{fileId}")
    public void videoResource(HttpServletResponse response, @PathVariable @NotEmpty String fileId) {
        //获取视频文件信息
        VideoInfoFile videoInfoFile = videoInfoFileService.getVideoInfoFileByFileId(fileId);
        // 获取视频文件路径
        String filePath = videoInfoFile.getFilePath();
        readFile(response, filePath + "/" + Constants.M3U8_NAME);

        //TODO 更新视频的阅读信息
    }
    /**
     * 获取视频ts文件
     * @param response
     * @param fileId
     * @param ts
     */
    @RequestMapping("/videoResource/{fileId}/{ts}")
    public void videoResourceTs(HttpServletResponse response,
                                @PathVariable @NotEmpty String fileId,
                                @PathVariable @NotEmpty String  ts) {
        //获取视频文件信息
        VideoInfoFile videoInfoFile = videoInfoFileService.getVideoInfoFileByFileId(fileId);
        // 获取视频文件路径
        String filePath = videoInfoFile.getFilePath();
        readFile(response, filePath + "/" + ts);
    }
}
